﻿// import cloudninja.metering.util.js

var cloudninja = cloudninja || {};
cloudninja.metering = cloudninja.metering || {};
cloudninja.metering.services = cloudninja.metering.services || {};


cloudninja.metering.services.Settings = {
    serviceUrlPath: "/odata"
};

// Actually it's a base class. Inheritance could to be implemented using Mootols or Prototype
cloudninja.metering.services.GenericService = {
    loadSingleResult: function (url, callback) {
        $.getJSON(url, function (rawResult) {
            var data = rawResult.value.length > 0 ? rawResult.value[0] : null;
            callback(rawResult, data);
        });
    },

    loadArrayResult: function (url, callback) {
        $.getJSON(url, function (rawResult) {
            var data = rawResult.value.length > 0 ? rawResult.value : [];
            callback(rawResult, data);
        });
    },

    prepareMonthlySeriesData: function (data) {
        var series = {};

        for (var i in meterTypes) {
            series[meterTypes[i]] = []; // points
        }

        $.each(data, function (index, value) {
            if (series[value.MeterTypeId]) {
                series[value.MeterTypeId].push([new Date(value.Year + '/' + value.Month + '/1'), value.Value]);
            }
        });

        var result = [];

        for (var i in meterTypes) {
            result.push(series[meterTypes[i]]);
        }

        return result;
    },

    prepareDailySeriesData: function (data, meterTypes) {
        var series = {};

        for (var i in meterTypes) {
            series[meterTypes[i]] = []; // points
        }

        $.each(data, function (index, value) {
            if (series[value.MeterTypeId]) {
                var date = new Date(value.TimePeriod.substr(0, 10));
                var formatted = moment(date).format("MM/DD/YYYY");
                series[value.MeterTypeId].push([formatted, value.Value]);
            }
        });

        var result = [];

        for (var i in meterTypes) {
            result.push(series[meterTypes[i]]);
        }

        return result;
    },

    getDailyStats: function (tenantId, meterTypes, startDateTime, endDateTime, callback) {
        var url = new cloudninja.metering.services.UrlBuilder()
            .query(cloudninja.metering.services.Settings.serviceUrlPath)
            .forEntity("MeterData")
            .withTenant(tenantId)
            .withMeterTypes(meterTypes)
            .withStartDateTime(startDateTime)
            .withEndDateTime(endDateTime)
            .orderBy("MeterTypeId")
            .build();

        cloudninja.metering.services.GenericService.loadArrayResult(url, function (result, data) {
            callback(result, data);
        });
    },

    getTotalDailyStats: function (meterTypes, startDateTime, endDateTime, callback) {
        var url = new cloudninja.metering.services.UrlBuilder()
            .query(cloudninja.metering.services.Settings.serviceUrlPath)
            .forEntity("TotalDailyView")
            .withMeterTypes(meterTypes)
            .withStartDateTime(startDateTime)
            .withEndDateTime(endDateTime)
            .orderBy("MeterTypeId")
            .build();

        cloudninja.metering.services.GenericService.loadArrayResult(url, function (result, data) {
            callback(result, data);
        });
    },

    getMonthlyStats: function (tenantId, meterTypes, callback) {
        var url = new cloudninja.metering.services.UrlBuilder()
            .query(cloudninja.metering.services.Settings.serviceUrlPath)
            .forEntity("MonthlyView")
            .withTenant(tenantId)
            .withMeterTypes(meterTypes)
            .orderBy("MeterTypeId")
            .build();

        cloudninja.metering.services.GenericService.loadArrayResult(url, function (result, data) {
            callback(result, data);
        });
    }
};


cloudninja.metering.services.DatabaseService = {
    getCurrentSize: function (tenantId, callback) {
        var url = new cloudninja.metering.services.UrlBuilder()
            .query(cloudninja.metering.services.Settings.serviceUrlPath)
            .forEntity("MeterData")
            .withTenant(tenantId)
            .withMeterType("dbs")
            .orderBy("TimePeriod desc")
            .takeTop(1)
            .build();

        cloudninja.metering.services.GenericService.loadSingleResult(url, function (result, data) {
            callback(result, data ? data.Value : null);
        });
    },

    getMonthlyAverage: function (tenantId, year, month, callback) {
        var url = new cloudninja.metering.services.UrlBuilder()
            .query(cloudninja.metering.services.Settings.serviceUrlPath)
            .forEntity("MonthlyView")
            .withTenant(tenantId)
            .withMeterType("dbs")
            .withYear(year)
            .withMonth(month)
            .takeTop(1)
            .build();

        cloudninja.metering.services.GenericService.loadSingleResult(url, function (result, data) {
            callback(result, data ? data.Value : null);
        });
    }
};


cloudninja.metering.services.StorageService = {
    getCurrentSize: function (tenantId, callback) {
        var url = new cloudninja.metering.services.UrlBuilder()
            .query(cloudninja.metering.services.Settings.serviceUrlPath)
            .forEntity("MeterData")
            .withTenant(tenantId)
            .withMeterType("stg")
            .orderBy("TimePeriod desc")
            .takeTop(1)
            .build();

        cloudninja.metering.services.GenericService.loadSingleResult(url, function (result, data) {
            callback(result, data ? data.Value : null);
        });
    },

    getMonthlyAverage: function (tenantId, year, month, callback) {
        var url = new cloudninja.metering.services.UrlBuilder()
            .query(cloudninja.metering.services.Settings.serviceUrlPath)
            .forEntity("MonthlyView")
            .withTenant(tenantId)
            .withMeterType("stg")
            .withYear(year)
            .withMonth(month)
            .takeTop(1)
            .build();

        cloudninja.metering.services.GenericService.loadSingleResult(url, function (result, data) {
            callback(result, data ? data.Value : null);
        });
    }
};


cloudninja.metering.services.BandwidthService = {
    getMonthlyTotal: function (tenantId, year, month, callback) {
        var url = new cloudninja.metering.services.UrlBuilder()
            .query(cloudninja.metering.services.Settings.serviceUrlPath)
            .forEntity("MonthlyView")
            .withTenant(tenantId)
            .withMeterType("bwe")
            .withYear(year)
            .withMonth(month)
            .takeTop(1)
            .build();

        cloudninja.metering.services.GenericService.loadSingleResult(url, function (result, data) {
            callback(result, data ? data.Value : null);
        });
    }
};


cloudninja.metering.services.UrlBuilder = function () {
    // entity-specific
    this._tenantId = "";
    this._meterTypes = [];
    this._month = 0;
    this._year = 0;
    this._startDateTime = null;
    this._endDateTime = null;

    // query-specific
    this._service = "";
    this._entity = "";
    this._top = 0;
    this._orderBy = "";

    this.query = function (service) {
        this._service = service;
        return this;
    };

    this.forEntity = function (entity) {
        this._entity = entity;
        return this;
    };

    this.withTenant = function (tenantId) {
        this._tenantId = tenantId;
        return this;
    };

    this.withMeterType = function (meterType) {
        this._meterTypes = [meterType];
        return this;
    };

    this.withMeterTypes = function (meterTypes) {
        this._meterTypes = meterTypes;
        return this;
    };

    this.withMonth = function (month) {
        this._month = month;
        return this;
    };

    this.withYear = function (year) {
        this._year = year;
        return this;
    };

    this.withStartDateTime = function (startDate) {
        this._startDateTime = startDate;
        return this;
    };

    this.withEndDateTime = function (endDate) {
        this._endDateTime = endDate;
        return this;
    };

    this.takeTop = function (top) {
        this._top = top;
        return this;
    };

    this.orderBy = function (orderBy) {
        this._orderBy = orderBy;
        return this;
    };

    this.build = function () {
        var url = this._service + "/" + this._entity + "?";
        var params = [];

        var filter = this._buildFilter();
        if (filter)
            params.push("$filter=" + filter);

        if (this._orderBy)
            params.push("$orderby=" + this._orderBy);

        if (this._top)
            params.push("$top=" + this._top);

        url += params.join("&");

        return url;
    };

    this._buildFilter = function () {
        var filterGroups = [];

        if (this._tenantId)
            filterGroups.push("TenantId eq '" + this._tenantId + "'");

        if (this._meterTypes.length > 0) {
            if (this._meterTypes.length == 1) {
                filterGroups.push("MeterTypeId eq '" + this._meterTypes[0] + "'");
            } else {
                var comparisons = this._meterTypes.map(function (value) {
                    return "MeterTypeId eq '" + value + "'";
                });

                filterGroups.push("(" + comparisons.join(" or ") + ")");
            }
        }

        if (this._month)
            filterGroups.push("Month eq " + this._month);

        if (this._year)
            filterGroups.push("Year eq " + this._year);

        if (this._startDateTime)
            filterGroups.push("TimePeriod ge datetime'" + cloudninja.metering.util.Util.dateToIso8601String(this._startDateTime) + "'");

        if (this._endDateTime)
            filterGroups.push("TimePeriod lt datetime'" + cloudninja.metering.util.Util.dateToIso8601String(this._endDateTime) + "'");

        return filterGroups.join(" and ");
    };
};